`timescale 1 ns / 1 ps

module ads8865_tb;

reg clk;
reg rst_n;
wire            co;
reg             rd_exec;
wire            dout;
wire             convst;
wire             sclk;
reg [ 15:0 ]     DATA;    
wire             rd_ready;

    initial begin
        clk<=0;
        rst_n<=1;
        #50 rst_n <=0;
        #100 rst_n <=1;
        rd_exec<=1'b0;
    end

        always #5 clk=~clk;

always #2000 DATA<=$random%65535;

Counter #(2000) sclk_gen_counter (.clk(clk), .rst_n(rst_n), .en( 1'b1), .cnt(),.co(co));

dac7881_drive u_ads8865_driver(
    .clk    (clk    ),
    .rst_n  (rst_n  ),
    .tx_exec(co),
    .mosi   (dout   ),
    .SYNC (convst ),
    .sclk   (sclk   ),
    .tx_data   (DATA   ),
    .tx_ready(rd_ready)
);

endmodule  

module dac7881_drive (
    input wire          clk, 
    input wire          rst_n,
    input logic          tx_exec,
    input wire  [15:0]  tx_data,
    output logic        tx_ready,
    output logic        SYNC,
    output logic        busy,
    output logic        sclk,
    output logic        mosi

);

logic                   sclk_gen;
reg         [ 7:0 ]     clk_cnt;
reg         [15:0 ]     DATA;
reg                cnt;

Counter #(2) sclk_gen_counter_dac7881 (.clk(clk), .rst_n(rst_n), .en( 1'b1), .cnt(cnt),.co(sclk_gen));

always@(posedge clk or negedge rst_n)begin
    if(!rst_n|!busy)
    sclk<=1'b0;
    else
        if(sclk_gen)
            sclk<=~sclk;
end



always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        busy<=1'b0;
    else begin
        if(tx_exec)
            busy<=1'b1;
        if(tx_ready)
            busy<=1'b0;
    end
end


always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
       mosi<=1'b0;
       DATA<=16'b0;
    end else begin
        if(tx_exec)
            DATA<=tx_data;
        else begin
           if(cnt==0&&busy&&sclk==1'b1)begin
            mosi<=DATA[15];
            DATA<=DATA<<1;
            end 
        end
    end
end

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)begin
        clk_cnt<=8'b0;
        SYNC<=1'b1;
        tx_ready<=1'b0;
    end
    else begin
        if (!busy)begin
            clk_cnt<=1'b0;
            tx_ready<=1'b0;
        end else
        if(busy&&sclk_gen&&sclk)begin
            clk_cnt+=1'b1;
            case (clk_cnt)
                8'd1:SYNC<=1'b0;
                8'd17:begin 
                    SYNC<=1'b1;
                    tx_ready<=1'b1;
                end
                default: ;
            endcase
        end
    end
end
endmodule

module Counter #(
    parameter M = 100
)(
    input wire clk, rst_n, en,
    output reg [$clog2(M) - 1 : 0] cnt,
    output wire co
);
    assign co = en & (cnt == M - 1);
    always@(posedge clk) begin
        if(!rst_n) cnt <= 1'b0;
        else if(en) begin
            if(cnt < M - 1) cnt <= cnt + 1'b1;
            else cnt <= 1'b0;
        end
    end
endmodule
